<?php

class Config
{
	/**
	 * Where non-persistent configuration is stored/cached.
	 */
	static protected $config = array();
	
	/**
	 * Whether we are connected to a database.
	 */
	static protected $database = false;
	
	/**
	 * Detects some basic environment settings.
	 *
	 * Part of the reason that makes this framework so easy to use is that this very
	 * function. By using a series of fairly smart algorithms it can automatically
	 * detect many environmental settings that otherwise would have to be entered by
	 * hand.
	 */
	static public function detectBasicConfig()
	{
		// Find base path
		$realpath = realpath(dirname(__FILE__).'/../../');
		$realpath .= (substr($realpath, -1) == '/' || substr($realpath, -1) == '\\') ? '' : '/'; 
		self::set('path', $realpath);
		
		// Detect context (CLI/CGI)
		if (array_key_exists('SHELL', $_ENV)) {
			self::set('context', 'cli');
		} else {
			self::set('context', 'web');
		}
		
		// Detect web-specific configuration
		if (self::get('context', 'web') == 'web') {
			// Try to find base uri
			$doc_root = realpath($_SERVER['DOCUMENT_ROOT']);
			if (substr($realpath, 0, strlen($doc_root)) == $doc_root) {
				self::set('uri', substr($realpath, strlen($doc_root)));
			}
		}
		
		// Detect Windows
		self::set('windows', stripos(PHP_OS, 'WIN') !== false);
		
		// Set include path
		$delim = (self::get('windows')) ? ';' : ':';
		ini_set('include_path', ini_get('include_path') . $delim . $realpath);
		
		Event::log('framework.config', 'Basic configuration loaded');
	}
	
	/**
	 * Loads and initializes database-dependent parts of the configuration.
	 */
	static public function loadPersistentConfig()
	{
		self::$database = true;
		
		if (@Config::get('firstRun', true)) {
			self::initDatabase();
		}
		
		if (isset($_REQUEST['debug']) && $_REQUEST['debug'] == self::get('debugTrigger')) {
			self::set('debug', true);
		}
	}
	
	/**
	 * Used to set a new configuration option.
	 * 
	 * Storable values include any valid PHP value for non-persistent storage and
	 * strings, numbers and booleans for persistent storage.
	 *
	 * @param string $setting Name/key of the setting
	 * @param mixed $value Actual value of the setting
	 * @param bool $persistent Whether or not to store setting persistently
	 */
	static public function set($setting, $value, $persistent = false)
	{
		self::$config[$setting] = $value;
		
		if ($persistent) {
			Data::update('config', array('value' => $value), array('key' => $setting), true);
		}
	}
	
	static public function get($setting, $default = null)
	{
		if (isset(self::$config[$setting])) {
			return self::$config[$setting];
		} else if (self::$database) {
			$value = Data::single('SELECT value FROM config WHERE key = '.Data::prepareValue($setting));
			
			if ($value !== null) {
				self::$config[$setting] = $value;
				return $value;
			}
		}
		
		return $default;
	}
	
	static public function initDatabase()
	{
		Data::query('CREATE TABLE IF NOT EXISTS config (key, value)');
		
		// Set firstRun to false in persistent storage, but not in non-persistent
		self::set('firstRun', false, true);
		self::set('firstRun', true);
		
		// Generate a code to be used as a debug trigger - if there is one in use already, use that one
		$debugTrigger = (isset($_REQUEST['debug'])) ? $_REQUEST['debug'] : md5(rand()*microtime(true));
		self::set('debugTrigger', $debugTrigger, true);
		Event::log('framework.config', 'Debug trigger initialized as '.self::get('debugTrigger'));
	}
}

?>